package org.dromara.system.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.sse.dto.SseMessageDto;
import org.dromara.common.sse.utils.SseMessageUtils;
import org.dromara.system.domain.SysChatRoomFriend;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.SysUserApply;
import org.dromara.system.domain.SysUserFriend;
import org.dromara.system.domain.bo.SysUserFriendBo;
import org.dromara.system.domain.enums.ApplyDeletedEnum;
import org.dromara.system.domain.enums.ApplyStatusEnum;
import org.dromara.system.domain.vo.SysUserApplyVo;
import org.dromara.system.domain.vo.SysUserFriendCheckVo;
import org.dromara.system.domain.vo.SysUserFriendVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.mapper.SysUserApplyMapper;
import org.dromara.system.mapper.SysUserFriendMapper;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.service.ISysChatMessageService;
import org.dromara.system.service.ISysChatRoomService;
import org.dromara.system.service.ISysUserFriendService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 用户好友信息Service业务层处理
 *
 * @author Lion Li
 * @date 2025-02-24
 */
@RequiredArgsConstructor
@Service
public class SysUserFriendServiceImpl implements ISysUserFriendService {
    private final SysUserFriendMapper baseMapper;
    private final SysUserApplyMapper applyMapper;
    private final SysUserMapper userMapper;
    private final ISysChatRoomService roomService;
    private final ISysChatMessageService messageService;
    private final ScheduledExecutorService scheduledExecutorService;

    /**
     * 查询用户好友信息
     *
     * @param id 主键
     * @return 用户好友信息
     */
    @Override
    public SysUserFriendVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 分页查询用户好友信息列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 用户好友信息分页列表
     */
    @Override
    public TableDataInfo<SysUserFriendVo> queryPageList(SysUserFriendBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<SysUserFriend> lqw = buildQueryWrapper(bo);
        Page<SysUserFriendVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的用户好友信息列表
     *
     * @param bo 查询条件
     * @return 用户好友信息列表
     */
    @Override
    public List<SysUserFriendVo> queryList(SysUserFriendBo bo) {
        LambdaQueryWrapper<SysUserFriend> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<SysUserFriend> buildQueryWrapper(SysUserFriendBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<SysUserFriend> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(SysUserFriend::getId);
        lqw.eq(bo.getUid() != null, SysUserFriend::getUid, bo.getUid());
        lqw.eq(bo.getFriendUid() != null, SysUserFriend::getFriendUid, bo.getFriendUid());
        return lqw;
    }

    /**
     * 新增用户好友信息
     *
     * @param bo 用户好友信息
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(SysUserFriendBo bo) {
        SysUserFriend add = MapstructUtils.convert(bo, SysUserFriend.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改用户好友信息
     *
     * @param bo 用户好友信息
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(SysUserFriendBo bo) {
        SysUserFriend update = MapstructUtils.convert(bo, SysUserFriend.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(SysUserFriend entity) {
        // TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并删除用户好友信息
     *
     * @param id      待删除的主键
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteWithValidById(Long id, boolean b) {
        if (b) {
            // TODO 做一些业务上的校验,判断是否需要校验
        }
        LoginUser loginUser = LoginHelper.getLoginUser();
        LambdaQueryWrapper<SysUserFriend> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUserFriend::getUid, loginUser.getUserId())
            .eq(SysUserFriend::getFriendUid, id).or()
            .eq(SysUserFriend::getUid, id)
            .eq(SysUserFriend::getFriendUid, loginUser.getUserId());
        List<SysUserFriend> userFriends = this.baseMapper.selectList(wrapper);
        if (CollectionUtil.isEmpty(userFriends)) {
            throw new ServiceException("好友不存在");
        }
        List<Long> ids = userFriends.stream().map(SysUserFriend::getId).collect(Collectors.toList());
        int result = baseMapper.deleteByIds(ids);
        // 禁用房间
        roomService.disableRoom(Arrays.asList(loginUser.getUserId(), id));
        return result;
    }

    /**
     * 校验并批量删除用户好友信息信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            // TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 批量检查是否是好友
     *
     * @param uidList uid list
     * @return SysUserFriendCheckVo
     */
    @Override
    public SysUserFriendCheckVo check(List<Long> uidList) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        LambdaQueryWrapper<SysUserFriend> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUserFriend::getUid, loginUser.getUserId());
        wrapper.in(SysUserFriend::getFriendUid, uidList);
        List<SysUserFriend> userFriends = this.baseMapper.selectList(wrapper);
        Set<Long> friendIds = userFriends.stream().map(SysUserFriend::getFriendUid).collect(Collectors.toSet());
        List<SysUserFriendCheckVo.FriendCheck> checkVoList = uidList.stream().map(uid -> {
            SysUserFriendCheckVo.FriendCheck friendCheck = new SysUserFriendCheckVo.FriendCheck();
            friendCheck.setUid(uid);
            friendCheck.setIsFriend(friendIds.contains(uid));
            return friendCheck;
        }).collect(Collectors.toList());
        return new SysUserFriendCheckVo(checkVoList);
    }

    @Override
    public SysUserApplyVo apply(String msg, Long targetUid) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        Long uid = loginUser.getUserId();
        // 是否是已经是好友关系
        LambdaQueryWrapper<SysUserFriend> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUserFriend::getUid, uid);
        wrapper.eq(SysUserFriend::getFriendUid, targetUid).last("limit 1");

        SysUserFriend friend = this.baseMapper.selectOne(wrapper);
        if (friend != null) {
            throw new ServiceException("已经是好友关系");
        }

        // 是否有待审批的申请记录(自己的)
        LambdaQueryWrapper<SysUserApply> wrapperSelfApply = new LambdaQueryWrapper<>();
        wrapperSelfApply.eq(SysUserApply::getUid, uid)
            .eq(SysUserApply::getTargetId, targetUid)
            .eq(SysUserApply::getStatus, ApplyStatusEnum.WAIT_APPROVAL.getCode())
            .eq(SysUserApply::getType, 1) // 申请加好友
            .notIn(true, SysUserApply::getDelStatus, ApplyDeletedEnum.applyDeleted())
            .notIn(false, SysUserApply::getDelStatus, ApplyDeletedEnum.targetDeleted()).last("limit 1");
        SysUserApplyVo selfApply = applyMapper.selectVoOne(wrapperSelfApply);
        // 已有好友申请记录
        if (ObjectUtil.isNotNull(selfApply)) {
            return null;
        }

        // 是否有待审批的申请记录(别人请求自己的)
        LambdaQueryWrapper<SysUserApply> wrapperOtherApply = new LambdaQueryWrapper<>();
        wrapperOtherApply.eq(SysUserApply::getUid, targetUid)
            .eq(SysUserApply::getTargetId, uid)
            .eq(SysUserApply::getStatus, ApplyStatusEnum.WAIT_APPROVAL.getCode())
            .eq(SysUserApply::getType, 1) // 申请加好友
            .notIn(false, SysUserApply::getDelStatus, ApplyDeletedEnum.applyDeleted())
            .notIn(true, SysUserApply::getDelStatus, ApplyDeletedEnum.targetDeleted()).last("limit 1");
        SysUserApplyVo otherApply = applyMapper.selectVoOne(wrapperOtherApply);
        if (ObjectUtil.isNotNull(otherApply)) {
            agree(otherApply.getId());
            return null;
        }
        // 申请添加好友
        SysUserApplyVo userApplyNew = new SysUserApplyVo();
        userApplyNew.setUid(uid);
        userApplyNew.setMsg(msg);
        userApplyNew.setTargetId(targetUid);
        userApplyNew.setStatus(ApplyStatusEnum.WAIT_APPROVAL.getCode());
        applyMapper.insert(MapstructUtils.convert(userApplyNew, SysUserApply.class));
        return userApplyNew;
    }

    @Override
    public TableDataInfo<SysUserApplyVo> appplyList(PageQuery pageQuery) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        Long uid = loginUser.getUserId(); // 当前登录用户id
        LambdaQueryWrapper<SysUserApply> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUserApply::getTargetId, uid)
            .eq(SysUserApply::getStatus, ApplyStatusEnum.WAIT_APPROVAL.getCode())
            .eq(SysUserApply::getType, 1) // 申请加好友
            .notIn(false, SysUserApply::getDelStatus, ApplyDeletedEnum.applyDeleted())
            .notIn(true, SysUserApply::getDelStatus, ApplyDeletedEnum.targetDeleted());
        Page<SysUserApplyVo> userApplyIPage = applyMapper.selectVoPage(pageQuery.build(), wrapper);

        // 读取申请列表
        readApplies(uid, userApplyIPage);

        return TableDataInfo.build(userApplyIPage);
    }

    private void readApplies(Long uid, Page<SysUserApplyVo> userApplyIPage) {
        List<Long> applyIds = userApplyIPage.getRecords().stream().map(SysUserApplyVo::getId)
            .collect(Collectors.toList());
        LambdaUpdateWrapper<SysUserApply> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(SysUserApply::getReadStatus, 1).in(SysUserApply::getId, applyIds)
            .eq(SysUserApply::getReadStatus, 0).eq(SysUserApply::getTargetId, uid);
        applyMapper.update(wrapper);

    }

    @Override
    public Long applyUnread() {
        LoginUser loginUser = LoginHelper.getLoginUser();
        LambdaQueryWrapper<SysUserApply> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUserApply::getTargetId, loginUser.getUserId())
            .eq(SysUserApply::getReadStatus, 1)
            .eq(SysUserApply::getDelStatus, ApplyDeletedEnum.NORMAL.getCode());
        return applyMapper.selectCount(wrapper);
    }

    @Override
    public void agree(Long id) {
        LoginUser loginUser = LoginHelper.getLoginUser();

        // 1. 校验申请记录
        SysUserApply apply = checkRecord(loginUser.getUserId(), id);

        // 2. 更新申请记录
        apply.setStatus(ApplyStatusEnum.AGREE.getCode());
        apply.setUpdateTime(new Date());
        applyMapper.updateById(apply);

        // 3. 创建双方好友关系
        createFriend(loginUser.getUserId(), id);

        // 4. 创建一个聊天房间
        SysChatRoomFriend roomFriend = roomService.createChatRoom(loginUser.getUserId(), id);

        // 5. 通知请求方已经处理好友申请
        scheduledExecutorService.schedule(() -> {
            SseMessageDto dto = new SseMessageDto();
            dto.setMessage("已经同意你的好友申请");
            dto.setUserIds(List.of(loginUser.getUserId(), apply.getUid()));
            SseMessageUtils.publishMessage(dto);
        }, 2, TimeUnit.SECONDS);

        // 6. 发送一条同意消息，我们已经是好友了，开始聊天吧
        messageService.sendMsg(roomFriend.getRoomId(), loginUser.getUserId());
    }

    private void createFriend(Long userId, Long id) {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Unimplemented method 'createFriend'");
    }

    @Override
    public int reject(Long id) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        SysUserApply apply = checkRecord(loginUser.getUserId(), id);
        apply.setStatus(ApplyStatusEnum.REJECT.getCode());
        apply.setUpdateTime(new Date());
        return applyMapper.updateById(apply);
    }

    @Override
    public int ignore(Long id) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        SysUserApply apply = checkRecord(loginUser.getUserId(), id);
        apply.setStatus(ApplyStatusEnum.IGNORE.getCode());
        apply.setUpdateTime(new Date());
        return applyMapper.updateById(apply);
    }

    @Override
    public int deleteApply(Long id) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        SysUserApply apply = checkRecord(loginUser.getUserId(), id);
        // 判断谁删除了这条记录
        ApplyDeletedEnum deletedEnum;
        if (ObjectUtil.equals(apply.getUid(), loginUser.getUserId())) {
            deletedEnum = ApplyDeletedEnum.APPLY_DELETED;
        } else {
            deletedEnum = ApplyDeletedEnum.TARGET_DELETED;
        }
        // 数据库已经当前删除方删了
        if (ObjectUtil.equals(apply.getDelStatus(), deletedEnum.getCode())) {
            return 0;
        }
        // 如果之前任意一方删除过 那就是都删了
        if (!ObjectUtil.equals(apply.getDelStatus(), ApplyDeletedEnum.NORMAL.getCode())) {
            deletedEnum = ApplyDeletedEnum.ALL_DELETED;
        }
        apply.setDelStatus(deletedEnum.getCode());
        return applyMapper.updateById(apply);
    }

    @Override
    public int updateRemark(Long targetUid, String remark) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        LambdaQueryWrapper<SysUserFriend> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUserFriend::getUid, loginUser.getUserId());
        wrapper.eq(SysUserFriend::getFriendUid, targetUid).last("limit 1");
        SysUserFriend friend = baseMapper.selectOne(wrapper);
        if (ObjectUtil.isNull(friend)) {
            throw new ServiceException("你们不是好友关系");
        }
        friend.setRemark(remark);
        return this.baseMapper.updateById(friend);
    }

    private SysUserApply checkRecord(Long uid, Long applyId) {
        SysUserApply apply = applyMapper.selectById(applyId);
        if (ObjectUtil.isNull(apply)) {
            throw new ServiceException("没有找到对应的申请记录");
        }
        return apply;
    }

    @Override
    public List<SysUserVo> findContacts(String phoneNumber, String nickname) {
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getPhonenumber, phoneNumber).or().eq(SysUser::getNickName, nickname);
        return userMapper.selectVoList(wrapper);
    }

    @Override
    public int updatePermission(SysUserFriendBo bo) {
        // 1. 校验好友是否存在
        LoginUser loginUser = LoginHelper.getLoginUser();
        LambdaQueryWrapper<SysUserFriend> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUserFriend::getUid, loginUser.getUserId())
            .eq(SysUserFriend::getFriendUid, bo.getFriendUid()).last("limit 1");
        SysUserFriend userFriend = this.baseMapper.selectOne(wrapper);
        if (ObjectUtil.isNull(userFriend)) {
            throw new ServiceException("你们不是好友！");
        }
        // 2. 修改好友权限
        userFriend.setHideMe(bo.getHideMe());
        userFriend.setHideFriend(bo.getHideFriend());
        return this.baseMapper.updateById(userFriend);
    }
}
